package com.mall.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mall.common.exception.BizIllegalException;
import com.mall.common.utils.BeanUtils;
import com.mall.common.utils.UserContext;
import com.mall.common.utils.JwtUtils;
import com.mall.constants.RoleConstant;
import com.mall.domain.dto.*;
import com.mall.domain.po.Address;
import com.mall.domain.po.Role;
import com.mall.domain.po.User;
import com.mall.domain.po.UserRole;
import com.mall.domain.response.Response;
import com.mall.domain.vo.UserLoginVO;
import com.mall.domain.vo.UserRoleVO;
import com.mall.enums.UserStatus;
import com.mall.mapper.UserMapper;
import com.mall.service.IAddressService;
import com.mall.service.RoleService;
import com.mall.service.UserRoleService;
import com.mall.service.UserService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final JwtUtils jwtUtils;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private UserMapper userMapper;
    @Resource
    private IAddressService addressService;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private RoleService roleService;

    @Value("${jwt.token-ttl}")
    private Long tokenTTL;

    @Override
    public Response<UserMessage> getUserMessage() {
        Long user1 = UserContext.getUser();
//        Object userIdObject = redisTemplate.opsForValue().get("userId");
//        Long userId = userIdObject instanceof Integer ? Long.valueOf(((Integer) userIdObject).longValue()) : (Long) userIdObject;
        User user = getById(user1);
        QueryWrapper<Address> addressQueryWrapper=new QueryWrapper<>();
        addressQueryWrapper.eq("user_id",user1);
        List<Address> addressList = addressService.list(addressQueryWrapper);
        UserMessage userMessage = new UserMessage();
        BeanUtils.copyProperties(user,userMessage);

        List<String> sb = new ArrayList<>();
        for (Address address:addressList){
            if (!address.getProvince().equals("北京")&&!address.getProvince().equals("天津")&&!address.getProvince().equals("重庆")&&!address.getProvince().equals("上海")){
                String s = address.getProvince() + address.getCity() + address.getTown() + address.getStreet();
                sb.add(s);
            }
            else {
                String s =  address.getCity() + address.getTown() + address.getStreet();
                sb.add(s);
            }
        }
        userMessage.setAddress(sb);
        return Response.success(userMessage);
    }

    @Override
    public Response<?> updateMessage(String username,String phone) {
        if (username==null||phone==null){
            return Response.fail("不能为空");
        }
        Long userid = UserContext.getUser();
        User user = new User();
        user.setId(userid).setPhone(phone).setUsername(username);
        updateById(user);
        return Response.success(user);
    }

    @Override
    public Response<?> freeze(UserBatchDTO userBatchDTO) {
        List<User> users = this.listByIds(userBatchDTO.getUserIds());
        for (User user : users) {
            user.setStatus(UserStatus.FROZEN);
            userMapper.updateById(user); // 循环更新每条记录
        }
        return Response.success();
    }

    @Override
    @Transactional
    public Response<?> deleteBatch(UserBatchDTO userBatchDTO) {
        this.removeBatchByIds(userBatchDTO.getUserIds());
        return Response.success();
    }

    @Override
    public Response<?> add(UserDTO userDTO) {
        User user = User.builder()
                .username(userDTO.getUsername())
                .password(userDTO.getPassword())
                .phone(userDTO.getPhone())
                .balance(0)
                .status(UserStatus.NORMAL)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        userMapper.save(user);
        Long userId = user.getId();

        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(Long.valueOf(userDTO.getRoleId()));
        userRoleService.save(userRole);

        return Response.success();
    }

    @Override
    public Response<Integer> getmoney() {

        Long userId = UserContext.getUser();
        User user = getById(userId);
        return Response.success(user.getBalance());
    }


    @Override
    public UserLoginVO login(LoginFormDTO loginFormDTO) {
        // 验证输入
        if (loginFormDTO == null || loginFormDTO.getUsername() == null || loginFormDTO.getPassword() == null) {
            throw new IllegalArgumentException("用户名或密码不能为空");
        }

        // 根据用户名查询用户
        User user = this.lambdaQuery().eq(User::getUsername, loginFormDTO.getUsername()).one();
        // 检查用户是否存在
        if (user == null) {
            throw new RuntimeException("当前登录用户不存在");
        }
        //验证用户状态
        if (user.getStatus()== UserStatus.FROZEN){
            throw new RuntimeException("当前登录用户已被冻结");
        }
        // 验证密码
        String password = loginFormDTO.getPassword();
        if (!password.equals(user.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        // 使用JwtUtils生成JWT令牌
        String token = jwtUtils.createToken(user.getId(), tokenTTL);
        // 构建返回对象
        UserLoginVO loginVO = new UserLoginVO();
        loginVO.setToken(token);
        loginVO.setUserId(user.getId());
        loginVO.setUsername(user.getUsername());
        loginVO.setBalance(user.getBalance());
        // 查询该用户的角色
        UserRole userRole = userRoleService.getOne
                (new QueryWrapper<UserRole>().eq("user_id", user.getId()));
        Role role = roleService.getOne
                (new QueryWrapper<Role>().eq("role_id", userRole.getRoleId()));

        if (!Objects.equals(role.getRoleKey(), loginFormDTO.getRole())){
            throw new RuntimeException("您的账号级别是" + role.getRoleName() + "，无法在此处登录~");
        }

        // 日志记录登录事件
        log.info("用户 {} 登录成功", user.getUsername());
        return loginVO;
    }



    @Override
    public void deductMoney(String pw, Integer cost) {
        log.info("开始扣款");
        // 1.校验密码
        User user = getById(UserContext.getUser());
        if(user == null || !pw.equals(user.getPassword())){
            // 密码错误
            throw new BizIllegalException("用户密码错误");
        }

        // 2.尝试扣款
        try {
            baseMapper.updateMoney(UserContext.getUser(), cost);
        } catch (Exception e) {
            throw new RuntimeException("扣款失败，可能是余额不足！", e);
        }
        log.info("扣款成功");
    }

    /**
     * 验证码 KEY 前缀
     */
    private static final String VERIFICATION_CODE_KEY_PREFIX = "verification_code:";

    @Override
    public void send(SendVerificationCodeReqDTO sendVerificationCodeReqDTO) {
        // 手机号
        String phone = sendVerificationCodeReqDTO.getPhone();

        // 构建验证码 redis key
        String key = VERIFICATION_CODE_KEY_PREFIX + phone;

        // 判断是否已发送验证码
        boolean isSent = redisTemplate.hasKey(key);
        if (isSent) {
            // 若之前发送的验证码未过期，则提示发送频繁
            throw new RuntimeException("请求太频繁，请5分钟后再试");
        }

        // 生成 6 位随机数字验证码
        String verificationCode = RandomUtil.randomNumbers(6);

        log.info("==> 手机号: {}, 已生成验证码：【{}】", phone, verificationCode);

        // 存储验证码到 redis, 并设置过期时间为 3 分钟
        redisTemplate.opsForValue().set(key, verificationCode, 5, TimeUnit.MINUTES);
    }

    /**
     * 用户注册
     */
    @Override
    @Transactional
    public void register(RegisterUserReqDTO registerUserReqDTO) {
        String phone = registerUserReqDTO.getPhone();

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("phone", phone);

        User user = userMapper.selectOne(userQueryWrapper);

        // 若已注册，则直接返回用户 ID
        if (Objects.nonNull(user)) {
            throw new RuntimeException("该号码已注册！");
        }

        // 构建验证码 redis key
        String key = VERIFICATION_CODE_KEY_PREFIX + phone;
        String code1 = String.valueOf(redisTemplate.opsForValue().get(key));

        if (!code1.equals(registerUserReqDTO.getCode())){
            throw new RuntimeException("验证码不正确！");
        }

        User user1 = new User();
        user1.setUsername(registerUserReqDTO.getUsername());
        user1.setPhone(registerUserReqDTO.getPhone());
        user1.setPassword(registerUserReqDTO.getPassword());
        user1.setBalance(0);
        user1.setStatus(UserStatus.NORMAL);
        user1.setCreateTime(LocalDateTime.now());
        user1.setUpdateTime(LocalDateTime.now());

        userMapper.save(user1);
        Long userId = user1.getId();

        // 给该账号分配普通角色
        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(RoleConstant.USER);
        userRoleService.save(userRole);

        //return Response.success();

    }
}
